/*
 * Copyright (c) 2008-2016, RF-Embedded GmbH
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
 * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "CPPrfeProtocolHandler.h"

#include "../helper/StringHelper.h"

using namespace CPPrfeReaderInterface;

CPPrfeProtocolHandler::CPPrfeProtocolHandler(IProtocolDeviceInterface *device)
{
    _Device = device;
    _Device->setDataReadListener(this);



    initMember();
    initParser();
}

CPPrfeProtocolHandler::~CPPrfeProtocolHandler()
{
    close();
}

void CPPrfeProtocolHandler::close()
{
    _Device->close();
}

//************************************************************** Reader-Common
/// <summary>
/// Retrieves the reader ID of the reader.
/// </summary>
/// <param name="readerID">Retrieved reader ID</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::getReaderID(ulong& readerID)
{
    Global::trc(_MinimumTraceLevel, "Get Reader ID - Trying to get Reader ID");

    readerID = 0;

    // reset last return code
    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_READER_COMMON, RFE_COM2_GET_SERIAL_NUMBER);
    if (!res){
        Global::trc(_MinimumTraceLevel, "Get Reader ID - NOK - Send");
        return res;
    }

    // wait for either the response or a timeout
    bool result = false;
    std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_READER_COMMON,
                                                                    RFE_COM2_GET_SERIAL_NUMBER), _ResponseTimeOut, result);
    if (!result){
        Global::trc(_MinimumTraceLevel, "Get Reader ID - NOK - Resp");
        return false;
    }

    // parse the response
    if (payl.size() != 4){
        Global::trc(_MinimumTraceLevel, "Get Reader ID - NOK - Payl");
        return false;
    }

    readerID = 0;
    readerID |= (((uint)payl[0]) << 24);
    readerID |= (((uint)payl[1]) << 16);
    readerID |= (((uint)payl[2]) << 8);
    readerID |= (uint)payl[3];

    Global::trc(_MinimumTraceLevel, "Get Reader ID - OK : Reader ID = " + StringHelper::toHexString(readerID));

    return true;
}

/// <summary>
/// Retrieves the reader type of the reader.
/// </summary>
/// <param name="readerType">Retrieved reader type</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::getReaderType(ulong& readerType)
{
    Global::trc(_MinimumTraceLevel, "Get Reader Type - Trying to get Reader Type");

    readerType = 0;

    // reset last return code
    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_READER_COMMON,
                           RFE_COM2_GET_READER_TYPE);
    if (!res){
        Global::trc(_MinimumTraceLevel, "Get Reader Type - NOK - Send");
        return res;
    }

    // wait for either the response or a timeout
    bool result = false;
    std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_READER_COMMON,
                                                                    RFE_COM2_GET_READER_TYPE), _ResponseTimeOut, result);
    if (!result){
        Global::trc(_MinimumTraceLevel, "Get Reader Type - NOK - Resp");
        return false;
    }

    // parse the response
    if (payl.size() != 4){
        Global::trc(_MinimumTraceLevel, "Get Reader Type - NOK - Payl");
        return false;
    }

    readerType = 0;
    readerType |= (((uint)payl[0]) << 24);
    readerType |= (((uint)payl[1]) << 16);
    readerType |= (((uint)payl[2]) << 8);
    readerType |= (uint)payl[3];

    Global::trc(_MinimumTraceLevel, "Get Reader Type - OK : Reader Type = " + StringHelper::toHexString(readerType));

    return true;
}

/// <summary>
/// Retrieves the hardware revision of the reader.
/// </summary>
/// <param name="hardwareRevision">Retrieved hardware revision</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::getHardwareRevision(ulong& hardwareRevision)
{
    Global::trc(_MinimumTraceLevel, "Get Hardware Rev - Trying to get hardware ID");

    hardwareRevision = 0;

    // reset last return code
    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_READER_COMMON,
                           RFE_COM2_GET_HARDWARE_REVISION);
    if (!res){
        Global::trc(_MinimumTraceLevel, "Get Hardware Rev - NOK - Send");
        return res;
    }

    // wait for either the response or a timeout
    bool result = false;
    std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_READER_COMMON,
                                                                    RFE_COM2_GET_HARDWARE_REVISION), _ResponseTimeOut, result);
    if (!result){
        Global::trc(_MinimumTraceLevel, "Get Hardware Rev - NOK - Resp");
        return false;
    }

    // parse the response
    if (payl.size() != 4){
        Global::trc(_MinimumTraceLevel, "Get Hardware Rev - NOK - Payl");
        return false;
    }

    // set the variable to the new value
    hardwareRevision = 0;
    hardwareRevision |= (((uint)payl[0]) << 24);
    hardwareRevision |= (((uint)payl[1]) << 16);
    hardwareRevision |= (((uint)payl[2]) << 8);
    hardwareRevision |= (uint)payl[3];

    Global::trc(_MinimumTraceLevel, "Get Hardware Rev - OK : Hardware Revision = " + StringHelper::toHexString(hardwareRevision));

    return true;
}

/// <summary>
/// Retrieves the software revision of the reader.
/// </summary>
/// <param name="softwareRevision">Retrieved software revision</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::getSoftwareRevision(ulong& softwareRevision)
{
    Global::trc(_MinimumTraceLevel, "Get Software Rev - Trying to get software ID");

    softwareRevision = 0;

    // reset last return code
    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_READER_COMMON,
                           RFE_COM2_GET_SOFTWARE_REVISION);
    if (res != true){
        Global::trc(_MinimumTraceLevel, "Get Software Rev - NOK - Send");
        return res;
    }

    // wait for either the response or a timeout
    bool result = false;
    std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_READER_COMMON,
                                                                    RFE_COM2_GET_SOFTWARE_REVISION), _ResponseTimeOut, result);
    if (!result){
        Global::trc(_MinimumTraceLevel, "Get Software Rev - NOK - Resp");
        return false;
    }

    // parse the response
    if (payl.size() != 4){
        Global::trc(_MinimumTraceLevel, "Get Software Rev - NOK - Payl");
        return false;
    }

    // set the variable to the new value
    softwareRevision = 0;
    softwareRevision |= (((uint)payl[0]) << 24);
    softwareRevision |= (((uint)payl[1]) << 16);
    softwareRevision |= (((uint)payl[2]) << 8);
    softwareRevision |= (uint)payl[3];

    Global::trc(_MinimumTraceLevel, "Get Software Rev - OK : Software Revision = " + StringHelper::toHexString(softwareRevision));

    return true;
}

/// <summary>
/// Retrieves the bootloader revision of the reader.
/// </summary>
/// <param name="bootloaderRevision">Retrieved bootloader revision</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::getBootloaderRevision(ulong& bootloaderRevision)
{
    Global::trc(_MinimumTraceLevel, "Get Bootloader Rev - Trying to get bootloader ID");

    bootloaderRevision = 0;

    // reset last return code
    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_READER_COMMON,
                           RFE_COM2_GET_BOOTLOADER_REVISION);
    if (res != true){
        Global::trc(_MinimumTraceLevel, "Get Bootloader Rev - NOK - Send");
        return res;
    }

    // wait for either the response or a timeout
    bool result = false;
    std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_READER_COMMON,
                                                                    RFE_COM2_GET_BOOTLOADER_REVISION), _ResponseTimeOut, result);
    if (!result){
        Global::trc(_MinimumTraceLevel, "Get Bootloader Rev - NOK - Resp");
        return false;
    }

    // parse the response
    if (payl.size() != 4){
        Global::trc(_MinimumTraceLevel, "Get Bootloader Rev - NOK - Payl");
        return false;
    }

    // set the variable to the new value
    bootloaderRevision = 0;
    bootloaderRevision |= (((uint)payl[0]) << 24);
    bootloaderRevision |= (((uint)payl[1]) << 16);
    bootloaderRevision |= (((uint)payl[2]) << 8);
    bootloaderRevision |= (uint)payl[3];

    Global::trc(_MinimumTraceLevel, "Get Bootloader Rev - OK : Bootloader Revision = " + StringHelper::toHexString(bootloaderRevision));

    return true;
}

/// <summary>
/// Retrieves the current running system of the reader.
/// </summary>
/// <param name="currentSystem">The current running sytem of the reader</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::getCurrentSystem(eRFE_CURRENT_SYSTEM& currentSystem)
{
    Global::trc(_MinimumTraceLevel, "Get Current System - Trying to get current System");

    currentSystem = RFE_SYS_FIRMWARE;

    // reset last return code
    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_READER_COMMON,
                           RFE_COM2_GET_CURRENT_SYSTEM);
    if (res != true){
        Global::trc(_MinimumTraceLevel, "Get Current System - NOK - Send");
        return res;
    }

    // wait for either the response or a timeout
    bool result = false;
    std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_READER_COMMON,
                                                                    RFE_COM2_GET_CURRENT_SYSTEM), _ResponseTimeOut, result);
    if (!result){
        Global::trc(_MinimumTraceLevel, "Get Current System - NOK - Resp");
        return false;
    }

    // parse the response
    if (payl.size() != 1){
        Global::trc(_MinimumTraceLevel, "Get Current System - NOK - Payl");
        return false;
    }

    currentSystem = (eRFE_CURRENT_SYSTEM)payl[0];

    Global::trc(_MinimumTraceLevel, "Get Current System - OK : System " + StringHelper::toString(currentSystem));

    return true;
}

/// <summary>
/// Retrieves the current state of the reader.
/// </summary>
/// <param name="currentState">Current state of the reader</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::getCurrentState(eRFE_CURRENT_READER_STATE& currentState)
{
    Global::trc(_MinimumTraceLevel, "Get Current State - Trying to get current State");

    currentState = RFE_STATE_IDLE;

    // reset last return code
    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_READER_COMMON,
                           RFE_COM2_GET_CURRENT_STATE);
    if (res != true){
        Global::trc(_MinimumTraceLevel, "Get Current State - NOK - Send");
        return res;
    }

    // wait for either the response or a timeout
    bool result = false;
    std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_READER_COMMON,
                                                                    RFE_COM2_GET_CURRENT_STATE), _ResponseTimeOut, result);
    if (!result){
        Global::trc(_MinimumTraceLevel, "Get Current State - NOK - Resp");
        return false;
    }

    // parse the response
    if (payl.size() != 1){
        Global::trc(_MinimumTraceLevel, "Get Current State - NOK - Payl");
        return false;
    }

    currentState = (eRFE_CURRENT_READER_STATE) payl[0];

    Global::trc(_MinimumTraceLevel, "Get Current State - OK : State " + StringHelper::toString(currentState));

    return true;
}

/// <summary>
/// Retrieves the status register of the reader.
/// </summary>
/// <param name="statusRegister">Status register of the reader</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::getStatusRegister ( ulonglong& statusRegister )
{
    Global::trc(_MinimumTraceLevel, "Get Status Register - Trying to get current State");

    statusRegister = 0;

    // reset last return code
    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_READER_COMMON,
                           RFE_COM2_GET_STATUS_REGISTER);
    if (res != true){
        Global::trc(_MinimumTraceLevel, "Get Status Register - NOK - Send");
        return res;
    }

    // wait for either the response or a timeout
    bool result = false;
    std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_READER_COMMON,
                                                                    RFE_COM2_GET_STATUS_REGISTER), _ResponseTimeOut, result);
    if (!result){
        Global::trc(_MinimumTraceLevel, "Get Status Register - NOK - Resp");
        return false;
    }

    // parse the response
    if (payl.size() != 8){
        Global::trc(_MinimumTraceLevel, "Get Status Register - NOK - Payl");
        return false;
    }

    statusRegister = 0;
    statusRegister |= (((ulonglong) payl[0]) << 56);
    statusRegister |= (((ulonglong) payl[1]) << 48);
    statusRegister |= (((ulonglong) payl[2]) << 40);
    statusRegister |= (((ulonglong) payl[3]) << 32);
    statusRegister |= (((ulonglong) payl[4]) << 24);
    statusRegister |= (((ulonglong) payl[5]) << 16);
    statusRegister |= (((ulonglong) payl[6]) << 8);
    statusRegister |= (ulonglong) payl[7];

    Global::trc(_MinimumTraceLevel, "Get Status Register - OK : Status Register = " + StringHelper::toHexString(statusRegister));

    return true;
}

/// <summary>
/// Retrieves the antenna count of the reader.
/// </summary>
/// <param name="count">Antenna count of the reader</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::getAntennaCount(byte& count)
{
    Global::trc(_MinimumTraceLevel, "Get Antenna Count - Trying to get antenna count");

    count = 0;

    // reset last return code
    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_READER_COMMON,
                           RFE_COM2_GET_ANTENNA_COUNT);
    if (res != true)
    {
        Global::trc(_MinimumTraceLevel, "Get Antenna Count - NOK - Send");
        return res;
    }

    // wait for either the response or a timeout
    bool result = false;
    std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_READER_COMMON,
                                                                    RFE_COM2_GET_ANTENNA_COUNT), _ResponseTimeOut, result);
    if (!result)
    {
        Global::trc(_MinimumTraceLevel, "Get Antenna Count - NOK - Resp");
        return false;
    }

    // parse the response
    if (payl.size() != 2)
    {
        Global::trc(_MinimumTraceLevel, "Get Antenna Count - NOK - Payl");
        return false;
    }

    count = (byte)payl[1];

    Global::trc(_MinimumTraceLevel, "Get Antenna Count - OK : Count " + StringHelper::toIntString(count));

    return true;
}

//************************************************************** Reader-RF
/// <summary>
/// Retrieves the attenuation settings of the reader.
/// </summary>
/// <param name="maxAttenuation">Maximum settable value for the attenuation</param>
/// <param name="currentAttenuation">Current set value for the attenuation</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::getAttenuation(ushort& maxAttenuation, ushort& currentAttenuation)
{
    Global::trc(_MinimumTraceLevel, "Get Attenuation - Trying to attenuation");

    maxAttenuation = currentAttenuation = 0;

    // reset last return code
    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_READER_RF,
            RFE_COM2_GET_ATTENUATION);
    if (res != true){
        Global::trc(_MinimumTraceLevel, "Get Attenuation - NOK - Send");
        return res;
    }

    // wait for either the response or a timeout
    bool result = false;
    std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_READER_RF,
            RFE_COM2_GET_ATTENUATION), _ResponseTimeOut, result);
    if (!result){
        Global::trc(_MinimumTraceLevel, "Get Attenuation - NOK - Resp");
        return false;
    }

    // parse the response
    if (payl.size() != 5 || ((eRFE_RET_VALUE)payl[0]) != RFE_RET_SUCCESS)
    {
        Global::trc(_MinimumTraceLevel, "Get Attenuation - NOK - Payl");
        _LastReturnCode = (eRFE_RET_VALUE) (byte) payl[0];
        return false;
    }

    // set the variable to the new value
    maxAttenuation = 0;
    maxAttenuation |= (ushort) (((ushort) payl[1]) << 8);
    maxAttenuation |= (ushort) payl[2];

    currentAttenuation = 0;
    currentAttenuation |= (ushort) (((ushort) payl[3]) << 8);
    currentAttenuation |= (ushort) payl[4];

    Global::trc(_MinimumTraceLevel, "Get Attenuation - OK : Max(" + StringHelper::toIntString(maxAttenuation) +
                                 ") - Cur(" + StringHelper::toIntString(currentAttenuation) + ")");

    return true;
}

/// <summary>
/// Retrieves the frequency table and the current set mode of the reader.
/// </summary>
/// <param name="mode">Current used mode</param>
/// <param name="maxFrequencyCount">Maximum count of frequency table entries</param>
/// <param name="frequencies">Frequency table</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::getFrequency(byte& mode, byte& maxFrequencyCount, std::vector<uint>& frequencies)
{
    Global::trc(_MinimumTraceLevel, "Get Frequency - Trying to frequency");

    mode = maxFrequencyCount = 0;

    // reset last return code
    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_READER_RF,
            RFE_COM2_GET_FREQUENCY);
    if (res != true){
        Global::trc(_MinimumTraceLevel, "Get Frequency - NOK - Send");
        return res;
    }

    // wait for either the response or a timeout
    bool result = false;
    std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_READER_RF,
            RFE_COM2_GET_FREQUENCY), _ResponseTimeOut, result);
    if (!result){
        Global::trc(_MinimumTraceLevel, "Get Frequency - NOK - Resp");
        return false;
    }

    // parse the response
    if (payl.size() < 5 || ((eRFE_RET_VALUE)payl[0]) != RFE_RET_SUCCESS)
    {
        Global::trc(_MinimumTraceLevel, "Get Frequency - NOK - Payl");
        _LastReturnCode = (eRFE_RET_VALUE) payl[0];
        return false;
    }

    mode = payl[1];
    maxFrequencyCount = payl[2];
    frequencies.clear();
    byte count = payl[3];
    byte index = 4;
    for (int i = 0; i < count; i++)
    {
        uint freq = 0;
        freq |= (((uint) payl[index++]) << 16);
        freq |= (((uint) payl[index++]) << 8);
        freq |= (uint) payl[index++];

        frequencies.push_back(freq);
    }

    Global::trc(_MinimumTraceLevel, "Get Frequency - OK : Mode(" + StringHelper::toIntString(mode) + ") - Max(" + StringHelper::toIntString(maxFrequencyCount) + ")");
    for (uint i = 0; i < frequencies.size(); i++)
    {
        uint f = frequencies[i];
        Global::trc(_MinimumTraceLevel, "Get Frequency - OK :     Freq(" + StringHelper::toIntString(f) + "kHz)");
    }

    return true;
}

/// <summary>
/// Retrieves the sensitivity settings of the reader.
/// </summary>
/// <param name="maxSensitivity">Maximum settable sensitivity</param>
/// <param name="minSensitivity">Mininim settable sensitivity</param>
/// <param name="currentSensitivity">Current set sensitivity</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::getSensitivity( short& maxSensitivity, short& minSensitivity, short& currentSensitivity )
{
    Global::trc(_MinimumTraceLevel, "Get Sensitivity - Trying to get Sensitivity");

    maxSensitivity = minSensitivity = currentSensitivity = 0;

    // reset last return code
    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_READER_RF,
            RFE_COM2_GET_SENSITIVITY);
    if (res != true){
        Global::trc(_MinimumTraceLevel, "Get Sensitivity - NOK - Send");
        return res;
    }

    // wait for either the response or a timeout
    bool result = false;
    std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_READER_RF,
            RFE_COM2_GET_SENSITIVITY), _ResponseTimeOut, result);
    if (!result){
        Global::trc(_MinimumTraceLevel, "Get Sensitivity - NOK - Resp");
        return false;
    }

    // parse the response
    if (payl.size() != 7 || ((eRFE_RET_VALUE)payl[0]) != RFE_RET_SUCCESS)
    {
        Global::trc(_MinimumTraceLevel, "Get Sensitivity - NOK - Payl");
        _LastReturnCode = (eRFE_RET_VALUE) payl[0];
        return false;
    }

    // set the variable to the new value
    maxSensitivity = 0;
    maxSensitivity |= (short) (((short) payl[1]) << 8);
    maxSensitivity |= (short) payl[2];

    minSensitivity = 0;
    minSensitivity |= (short) (((short) payl[3]) << 8);
    minSensitivity |= (short) payl[4];

    currentSensitivity = 0;
    currentSensitivity |= (short) (((short) payl[5]) << 8);
    currentSensitivity |= (short) payl[6];

    Global::trc(_MinimumTraceLevel, "Get Sensitivity - OK : Max(" + StringHelper::toIntString(maxSensitivity) +
                                 ") - Min(" + StringHelper::toIntString(minSensitivity) +
                                 ") - Cur" + StringHelper::toIntString(currentSensitivity) + ")");

    return true;
}

/// <summary>
/// Retrieves the LBT params of the reader.
/// </summary>
/// <param name="listenTime">Listen time in msecs</param>
/// <param name="idleTime">Idle time in msecs</param>
/// <param name="maxAllocTime">Maximum allocation time in msecs</param>
/// <param name="rssiThreshold">RSSI threshold</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::getLbtParams(ushort& listenTime, ushort& idleTime, ushort& maxAllocTime, short& rssiThreshold)
{
    Global::trc(_MinimumTraceLevel, "Get Lbt Params - Trying to get Lbt Params");

    listenTime = idleTime = maxAllocTime = 0;
    rssiThreshold = 0;

    // reset last return code
    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_READER_RF,
            RFE_COM2_GET_LBT_PARAMS);
    if (res != true)
    {
        Global::trc(_MinimumTraceLevel, "Get Lbt Params - NOK - Send");
        return res;
    }

    // wait for either the response or a timeout
    bool result = false;
    std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_READER_RF,
            RFE_COM2_GET_LBT_PARAMS), _ResponseTimeOut, result);
    if (!result)
    {
        Global::trc(_MinimumTraceLevel, "Get Lbt Params - NOK - Resp");
        return false;
    }

    // parse the response
    if (payl.size() != 9 || ((eRFE_RET_VALUE)payl[0]) != RFE_RET_SUCCESS)
    {
        Global::trc(_MinimumTraceLevel, "Get Lbt Params - NOK - Payl");
        _LastReturnCode = (eRFE_RET_VALUE)payl[0];
        return false;
    }

    // set the variable to the new value
    listenTime = 0;
    listenTime |= (ushort)(((ushort)payl[1]) << 8);
    listenTime |= (ushort)payl[2];

    idleTime = 0;
    idleTime |= (ushort)(((ushort)payl[3]) << 8);
    idleTime |= (ushort)payl[4];

    maxAllocTime = 0;
    maxAllocTime |= (ushort)(((ushort)payl[5]) << 8);
    maxAllocTime |= (ushort)payl[6];

    rssiThreshold = 0;
    rssiThreshold |= (short)(((short)payl[7]) << 8);
    rssiThreshold |= (short)payl[8];

    Global::trc(_MinimumTraceLevel, "Get Lbt Params - OK : Listen Time " + StringHelper::toIntString(listenTime) +
                                 " Idle Time " + StringHelper::toIntString(idleTime) +
                                 " Maximum Allocation Time " + StringHelper::toIntString(maxAllocTime) +
                                 " RSSI Threshold " + StringHelper::toIntString(rssiThreshold));

    return true;
}

/// <summary>
/// Sets the attenuation setting of the reader
/// </summary>
/// <param name="value">The new attenuation value</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::setAttenuation(ushort value)
{
    Global::trc(_MinimumTraceLevel, "Set Attenuation - Trying to set output power to " + StringHelper::toIntString(value));

    std::vector<byte> payload;
    payload.resize(2);
    payload[0] = (byte)(value >> 8);
    payload[1] = (byte)(value);

    // reset last return code
    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_READER_RF,
            RFE_COM2_SET_ATTENUATION, payload);
    if (res != true)
    {
        Global::trc(_MinimumTraceLevel, "Set Attenuation - NOK - Send");
        return res;
    }

    // wait for either the response or a timeout
    bool result = false;
    std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_READER_RF,
            RFE_COM2_SET_ATTENUATION), _ResponseTimeOut, result);
    if (!result)
    {
        Global::trc(_MinimumTraceLevel, "Set Attenuation - NOK - Resp");
        return false;
    }

    // parse the response
    if (payl.size() == 0 || ((eRFE_RET_VALUE)payl[0]) != RFE_RET_SUCCESS)
    {
        Global::trc(_MinimumTraceLevel, "Set Attenuation - NOK - Payl");
        _LastReturnCode = (eRFE_RET_VALUE)payl[0];
        return false;
    }

    Global::trc(_MinimumTraceLevel, "Set Attenuation - OK");

    return true;
}

//************************************************************** Reader-Control
/// <summary>
/// Reboots the reader
/// </summary>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::reboot()
{
    Global::trc(_MinimumTraceLevel, "Reboot - Trying to reboot");

    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_READER_CONTROL,
            RFE_COM2_REBOOT);
    if (res != true){
        Global::trc(_MinimumTraceLevel, "Reboot - NOK - Send");
        return res;
    }

    Sleeper::msleep(50);

    return true;
}

/// <summary>
/// Sets the heartbeat settings of the reader
/// </summary>
/// <param name="on">Specifies if the reader should send a heartbeat</param>
/// <param name="interval">Specifies the interval of the heartbeat</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::setHeartBeat(bool on, ushort interval)
{
    Global::trc(_MinimumTraceLevel, "Set Heartbeat - Trying to set heartbeat " + std::string((on) ? "ON" : "OFF"));

    std::vector<byte> payload;
    if (interval == 0)
    {
        payload.resize(1);
        payload[0] = (byte)((on) ? HEARTBEAT_ON : HEARTBEAT_OFF);
    }
    if (interval != 0)
    {
        payload.resize(3);
        payload[0] = (byte)((on) ? HEARTBEAT_ON : HEARTBEAT_OFF);
        payload[1] = (byte) (interval >> 8);
        payload[2] = (byte) (interval);
    }

    // reset last return code
    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_READER_CONTROL,
            RFE_COM2_SET_HEARTBEAT, payload);
    if (res != true){
        Global::trc(_MinimumTraceLevel, "Set Heartbeat - NOK - Send");
        return res;
    }

    // wait for either the response or a timeout
    bool result = false;
    std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_READER_CONTROL,
            RFE_COM2_SET_HEARTBEAT), _ResponseTimeOut, result);
    if (!result){
        Global::trc(_MinimumTraceLevel, "Set Heartbeat - NOK - Resp");
        return false;
    }

    // parse the response
    if (payl.size() == 0 || ((eRFE_RET_VALUE)payl[0])
            != RFE_RET_SUCCESS)
    {
        Global::trc(_MinimumTraceLevel, "Set Heartbeat - NOK - Payl");
        _LastReturnCode = (eRFE_RET_VALUE) (byte) payl[0];
        return false;
    }

    Global::trc(_MinimumTraceLevel, "Set Heartbeat - OK");

    return true;

}

/// <summary>
/// Sets the antenna power of the reader
/// </summary>
/// <param name="on">Specifies if the antenna power should be activated</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::setAntennaPower(bool on)
{
    Global::trc(_MinimumTraceLevel, "Set Antenna - Trying to set antenna power " + std::string((on) ? "ON" : "OFF"));

    std::vector<byte> payload;
    payload.resize(1);
    payload[0] = (byte) ((on) ? ANTENNA_ON : ANTENNA_OFF);

    // reset last return code
    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_READER_CONTROL,
            RFE_COM2_SET_ANTENNA_POWER, payload);
    if (res != true){
        Global::trc(_MinimumTraceLevel, "Set Antenna - NOK - Send");
        return res;
    }

    // wait for either the response or a timeout
    bool result = false;
    std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_READER_CONTROL,
            RFE_COM2_SET_ANTENNA_POWER), _ResponseTimeOut, result);
    if (!result){
        Global::trc(_MinimumTraceLevel, "Set Antenna - NOK - Resp");
        return false;
    }

    // parse the response
    if (payl.size() == 0 || ((eRFE_RET_VALUE)payl[0]) != RFE_RET_SUCCESS)
    {
        Global::trc(_MinimumTraceLevel, "Set Antenna - NOK - Payl");
        _LastReturnCode = (eRFE_RET_VALUE) (byte) payl[0];
        return false;
    }

    Global::trc(_MinimumTraceLevel, "Set Antenna - OK");

    return true;
}

/// <summary>
/// Saves the settings permanent on the reader
/// </summary>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::saveSettingsPermanent()
{
    Global::trc(_MinimumTraceLevel, "Save Settings - Trying save settings permanent");

    // reset last return code
    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_READER_CONTROL,
            RFE_COM2_SAVE_SETTINGS_PERMANENT);
    if (res != true){
        Global::trc(_MinimumTraceLevel, "Save Settings - NOK - Send");
        return res;
    }

    // wait for either the response or a timeout
    bool result = false;
    std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_READER_CONTROL,
            RFE_COM2_SAVE_SETTINGS_PERMANENT), _ResponseTimeOut, result);
    if (!result){
        Global::trc(_MinimumTraceLevel, "Save Settings - NOK - Resp");
        return false;
    }

    // parse the response
    if (payl.size() == 0 || ((eRFE_RET_VALUE)payl[0])
            != RFE_RET_SUCCESS)
    {
        Global::trc(_MinimumTraceLevel, "Save Settings - NOK - Payl");
        _LastReturnCode = (eRFE_RET_VALUE) payl[0];
        return false;
    }

    Global::trc(_MinimumTraceLevel, "Save Settings - OK");

    return true;

}

/// <summary>
/// Restores the factory settings of the reader
/// </summary>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::restoreFactorySettings()
{
    Global::trc(_MinimumTraceLevel, "Restore Settings - Trying to restore settings");

    // reset last return code
    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_READER_CONTROL,
            RFE_COM2_RESTORE_FACTORY_SETTINGS);
    if (res != true){
        Global::trc(_MinimumTraceLevel, "Restore Settings - NOK - Send");
        return res;
    }

    // wait for either the response or a timeout
    bool result = false;
    std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_READER_CONTROL,
            RFE_COM2_RESTORE_FACTORY_SETTINGS), _ResponseTimeOut, result);
    if (!result){
        Global::trc(_MinimumTraceLevel, "Restore Settings - NOK - Resp");
        return false;
    }

    // parse the response
    if (payl.size() == 0 || ((eRFE_RET_VALUE)payl[0])
            != RFE_RET_SUCCESS)
    {
        Global::trc(_MinimumTraceLevel, "Restore Settings - NOK - Payl");
        _LastReturnCode
                = (eRFE_RET_VALUE) payl[0];
        return false;
    }

    Global::trc(_MinimumTraceLevel, "Restore Settings - OK");

    return true;
}

/// <summary>
/// Retrieves a parameter from the reader at the given address
/// </summary>
/// <param name="address">Address of the paremeter</param>
/// <param name="value">Retrieved value of the parameter</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::getParam(ushort address, std::vector<byte>& value)
{
    Global::trc(_MinimumTraceLevel, "Get Param - Trying to get param of address " + StringHelper::toIntString(address));

    std::vector<byte> payload;
    payload.resize(2);
    payload[0] = (byte) (address >> 8);
    payload[1] = (byte) (address);

    // reset last return code
    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_READER_CONTROL,
            RFE_COM2_GET_PARAM, payload);
    if (res != true){
        Global::trc(_MinimumTraceLevel, "Get Param - NOK - Send");
        return res;
    }

    // wait for either the response or a timeout
    bool result = false;
    std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_READER_CONTROL,
            RFE_COM2_GET_PARAM), _ResponseTimeOut, result);
    if (!result){
        Global::trc(_MinimumTraceLevel, "Get Param - NOK - Resp");
        return false;
    }

    // parse the response
    if (payl.size() == 0 || ((eRFE_RET_VALUE)payl[0])
            != RFE_RET_SUCCESS)
    {
        Global::trc(_MinimumTraceLevel, "Get Param - NOK - Payl");
        _LastReturnCode = (eRFE_RET_VALUE) payl[0];
        return false;
    }

    value.resize(payl[1]);
    Array::copy(payl, 2, value, 0, value.size());

    Global::trc(_MinimumTraceLevel, "Get Param - OK : " + StringHelper::toString(value));

    return true;
}


//************************************************************** GPIO
/// <summary>
/// Retrieves the GPIO capabillities of the reader
/// </summary>
/// <param name="mask">Bit mask of available GPIOs</param>
/// <param name="output">Bit mask of GPIOs that are available as output</param>
/// <param name="input">Bit mask of GPIOs that are available as input</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::getGPIOCaps(ulong& mask, ulong& output, ulong& input)
{
    mask = output = input = 0;

    Global::trc(6, "Get GPIO Caps - Trying to get GPIO Caps");

    // reset the flag
    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_READER_GPIO,
            RFE_COM2_GET_GPIO_CAPS);
    if (res != true){
        Global::trc(_MinimumTraceLevel, "Get GPIO Caps - NOK - Send");
        return res;
    }

    // wait for either the flag or a timeout
    bool result = false;
    std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_READER_GPIO,
            RFE_COM2_GET_GPIO_CAPS), _ResponseTimeOut, result);
    if (!result){
        Global::trc(_MinimumTraceLevel, "Get GPIO Caps - NOK - Resp");
        return false;
    }

    if (payl.size() != 12){
        Global::trc(_MinimumTraceLevel, "Get GPIO Caps - NOK - Payl");
        return false;
    }

    mask = 0;
    mask |= (((ulong) (byte) payl[0]) << 24);
    mask |= (((ulong) (byte) payl[1]) << 16);
    mask |= (((ulong) (byte) payl[2]) << 8);
    mask |= (ulong) (byte) payl[3];

    output = 0;
    output |= (((ulong) (byte) payl[4]) << 24);
    output |= (((ulong) (byte) payl[5]) << 16);
    output |= (((ulong) (byte) payl[6]) << 8);
    output |= (ulong) (byte) payl[7];

    input = 0;
    input |= (((ulong) (byte) payl[8]) << 24);
    input |= (((ulong) (byte) payl[9]) << 16);
    input |= (((ulong) (byte) payl[10]) << 8);
    input |= (ulong) (byte) payl[11];

    Global::trc(6, "Get GPIO Caps - OK");

    return true;
}

/// <summary>
/// Retrieves the current set GPIO direction
/// </summary>
/// <param name="direction">Bit mask of the current direction, 1 = output, 2 = input</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::getGPIODirection(ulong& direction)
{
    direction = 0;

    Global::trc(_MinimumTraceLevel, "Get GPIO Direction - Trying to get GPIO Direction");

    // reset the flag
    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_READER_GPIO,
            RFE_COM2_GET_GPIO_DIRECTION);
    if (res != true){
        Global::trc(_MinimumTraceLevel, "Get GPIO Direction - NOK - Send");
        return res;
    }

    // wait for either the flag or a timeout
    bool result = false;
    std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_READER_GPIO,
            RFE_COM2_GET_GPIO_DIRECTION), _ResponseTimeOut, result);
    if (!result){
        Global::trc(_MinimumTraceLevel, "Get GPIO Direction - NOK - Resp");
        return false;
    }

    if (payl.size() != 4){
        Global::trc(_MinimumTraceLevel, "Get GPIO Direction - NOK - Payl");
        return false;
    }

    direction = 0;
    direction |= (((ulong) (byte) payl[0]) << 24);
    direction |= (((ulong) (byte) payl[1]) << 16);
    direction |= (((ulong) (byte) payl[2]) << 8);
    direction |= (ulong) (byte) payl[3];

    Global::trc(_MinimumTraceLevel, "Get GPIO Direction - OK");

    return true;
}

/// <summary>
/// Retrieves the current level of the GPIO pins
/// </summary>
/// <param name="mask">Bit mask of the current level</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::getGPIO(ulong& mask)
{
    mask = 0;

    Global::trc(_MinimumTraceLevel, "Get GPIO - Trying to get GPIO");

    // reset the flag
    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_READER_GPIO,
            RFE_COM2_GET_GPIO);
    if (res != true){
        Global::trc(_MinimumTraceLevel, "Get GPIO - NOK - Send");
        return res;
    }

    // wait for either the flag or a timeout
    bool result = false;
    std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_READER_GPIO,
            RFE_COM2_GET_GPIO), _ResponseTimeOut, result);
    if (!result){
        Global::trc(_MinimumTraceLevel, "Get GPIO - NOK - Resp");
        return false;
    }

    if (payl.size() != 4){
        Global::trc(_MinimumTraceLevel, "Get GPIO - NOK - Payl");
        return false;
    }

    mask = 0;
    mask |= (((ulong) (byte) payl[0]) << 24);
    mask |= (((ulong) (byte) payl[1]) << 16);
    mask |= (((ulong) (byte) payl[2]) << 8);
    mask |= (ulong) (byte) payl[3];

    Global::trc(_MinimumTraceLevel, "Get GPIO Direction - OK");

    return true;

}


//************************************************************** Tag-Functions
/// <summary>
/// Executes a single inventory at the reader.
/// </summary>
/// <param name="tagList">List of found tags</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::doSingleInventory(std::vector<CPPrfeTagEvent>& tagList)
{
    Global::trc(_MinimumTraceLevel, "Single Inventory - Trying to do an inventory");

    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_TAG_FUNCTIONS,
            RFE_COM2_INVENTORY_SINGLE);
    if (res != true){
        Global::trc(_MinimumTraceLevel, "Single Inventory - NOK - Send");
        return res;
    }

    byte epcCount = 0;
    byte epcsReceived = 0;

    while (true)
    {

        // wait for either the response or a timeout
        bool result = false;
        std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_TAG_FUNCTIONS,
                RFE_COM2_INVENTORY_SINGLE), _ResponseTimeOut, result);
        if (!result)
        {
            Global::trc(_MinimumTraceLevel, "Single Inventory - NOK - Resp");
            return false;
        }

        // parse the response
        if (payl.size() == 0 || ((eRFE_RET_VALUE)payl[0]) != RFE_RET_SUCCESS)
        {
            Global::trc(_MinimumTraceLevel, "Single Inventory - NOK - Payl");
            _LastReturnCode = (eRFE_RET_VALUE)payl[0];
            return false;
        }

        epcCount = payl[1];
        byte epcsInPackage = payl[2];
        byte index = 3;

        for (int i = 0; i < epcsInPackage; i++)
        {
            byte infoLength = payl[index];
            std::vector<byte> temp;
            temp.resize(infoLength);
            Array::copy(payl, index + 1, temp, 0, infoLength);

            CPPrfeTagEvent tagEvent;
            bool ok  = parseTagEvent(temp, tagEvent);

            if (!ok)
                return false;

            tagList.push_back(tagEvent);
            index += payl[index];
            index++;
        }
        epcsReceived += epcsInPackage;

        Global::trc(_MinimumTraceLevel, "Single Inventory - OK : Package Count(" + StringHelper::toIntString(epcsInPackage) + ")");

        if (epcsReceived >= epcCount)
            break;
    }

    Global::trc(_MinimumTraceLevel, "Single Inventory - OK : Count(" + StringHelper::toIntString(epcCount) + ")");
    for (uint i = 0; i < tagList.size(); i++)
    {
        CPPrfeTagEvent t = tagList[i];
        Global::trc(_MinimumTraceLevel, "Single Inventory - OK :     EPC: " + StringHelper::toString(t.tagId));
    }
    return true;
}

/// <summary>
/// Sets the cyclic inventory on or off
/// </summary>
/// <param name="on">Cyclic inventory mode</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::setCyclicInventory(bool on)
{
    Global::trc(_MinimumTraceLevel, "Cyclic Inventory - Trying to set cyclic inventory to " + StringHelper::toIntString(on));

    std::vector<byte> payload;
    payload.resize(1);
    if (on)
        payload[0] = (byte) INVENTORY_ON;
    else
        payload[0] = (byte) INVENTORY_OFF;

    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_TAG_FUNCTIONS,
            RFE_COM2_INVENTORY_CYCLIC, payload);
    if (res != true){
        Global::trc(_MinimumTraceLevel, "Cyclic Inventory - NOK - Send");
        return res;
    }

    // wait for either the response or a timeout
    bool result = false;
    std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_TAG_FUNCTIONS,
            RFE_COM2_INVENTORY_CYCLIC), _ResponseTimeOut, result);
    if (!result){
        Global::trc(_MinimumTraceLevel, "Cyclic Inventory - NOK - Resp");
        return false;
    }

    // parse the response
    if (payl.size() == 0 || ((eRFE_RET_VALUE)payl[0])
            != RFE_RET_SUCCESS)
    {
        Global::trc(_MinimumTraceLevel, "Cyclic Inventory - NOK - Payl");
        _LastReturnCode
                = (eRFE_RET_VALUE) payl[0];
        return false;
    }

    Global::trc(_MinimumTraceLevel, "Cyclic Inventory - OK");

    return true;
}

/// <summary>
/// Reads data from a tag.
/// </summary>
/// <param name="epc">EPC of the specified tag</param>
/// <param name="mem_bank">Memory bank where to read data from</param>
/// <param name="address">Address within the memory bank</param>
/// <param name="passwd">The access password to read from the tag</param>
/// <param name="count">The count of data that should be read</param>
/// <param name="data">The read data</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::readFromTag(std::vector<byte> epc, byte mem_bank, ushort address, std::vector<byte> passwd, byte count, std::vector<byte>& data)
{
    Global::trc(_MinimumTraceLevel, "Read From Tag - Trying to read from tag " + StringHelper::toString(epc) + " from memory bank "
            + StringHelper::toIntString(mem_bank) + " and address " + StringHelper::toIntString(address) + " the count " + StringHelper::toIntString(count));

    if (passwd.size() != 4){
        Global::trc(_MinimumTraceLevel, "Read From Tag - NOK - Data");
        return false;
    }


    int index = 0;
    std::vector<byte> payload;
    payload.resize(5 + epc.size() + passwd.size());

    payload[index++] = (byte) epc.size();
    Array::copy(epc, 0, payload, index, epc.size());
    index += epc.size();

    payload[index++] = (byte) mem_bank;
    payload[index++] = (byte) (address >> 8);
    payload[index++] = (byte) address;
    Array::copy(passwd, 0, payload, index, passwd.size());
    index += passwd.size();

    payload[index++] = (byte) count;

    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_TAG_FUNCTIONS,
            RFE_COM2_READ_FROM_TAG, payload);
    if (res != true){
        Global::trc(_MinimumTraceLevel, "Read From Tag - NOK - Send");
        return res;
    }

    // wait for either the response or a timeout
    bool result = false;
    std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_TAG_FUNCTIONS,
            RFE_COM2_READ_FROM_TAG), _ResponseTimeOut * 4, result);
    if (!result){
        Global::trc(_MinimumTraceLevel, "Read From Tag - NOK - Resp");
        return false;
    }

    // parse the response
    if (payl.size() == 0 || (((eRFE_RET_VALUE)payl[0])
            != RFE_RET_SUCCESS) && (((eRFE_RET_VALUE)payl[0])
            != RFE_RET_RESULT_PENDING))
    {
        Global::trc(_MinimumTraceLevel, "Read From Tag - NOK - Payl");
        _LastReturnCode = (eRFE_RET_VALUE) payl[0];
        return false;
    }

    if (((eRFE_RET_VALUE)payl[0]) == RFE_RET_SUCCESS)
    {
        data.resize(payl[1]);
        Array::copy(payl, 2, data, 0, payl[1]);
    }
    else if (((eRFE_RET_VALUE)payl[0]) == RFE_RET_RESULT_PENDING)
    {
        if (payl.size() != 2)
        {
            Global::trc(0, "Read From Tag - NOK - Payl");
            _LastReturnCode = (eRFE_RET_VALUE) payl[0];
            return false;
        }

        bool p_result = false;
        std::vector<byte> pendingResp = _PendingMessageQueue.waitForMessage(payl[1], _ResponseTimeOut * 10, p_result);
        if (!p_result)
        {
            Global::trc(_MinimumTraceLevel, "Read From Tag - NOK - Resp");
            return false;
        }

        if (pendingResp.size() == 0 || ((eRFE_RET_VALUE)pendingResp[0])
            != RFE_RET_SUCCESS)
        {
            Global::trc(_MinimumTraceLevel, "Read From Tag - NOK - Payl");
            _LastReturnCode = (eRFE_RET_VALUE)pendingResp[0];
            return false;
        }

        data.resize(pendingResp[1]);
        Array::copy(pendingResp, 2, data, 0, pendingResp[1]);
    }

    Global::trc(_MinimumTraceLevel, "Read From Tag - OK : Read the data from the tag:" + StringHelper::toString(data));

    return true;
}

/// <summary>
/// Writes data to the a tag.
/// </summary>
/// <param name="epc">EPC of the specified tag</param>
/// <param name="mem_bank">Memory bank where data should be written to</param>
/// <param name="address">Address within the memory bank</param>
/// <param name="passwd">The access password to write to the tag</param>
/// <param name="data">The data that should be written</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::writeToTag(std::vector<byte> epc, byte mem_bank, ushort address, std::vector<byte> passwd, std::vector<byte> data)
{
    Global::trc(_MinimumTraceLevel, "Write To Tag - Trying to write to tag " + StringHelper::toString(epc) + " at bank "
            + StringHelper::toIntString(mem_bank) + " and address " + StringHelper::toIntString(address) + " the bytes " + StringHelper::toString(data));

    if (passwd.size() != 4){
        Global::trc(_MinimumTraceLevel, "Write To Tag - NOK - Data");
        return false;
    }

    int index = 0;
    std::vector<byte> payload;
    payload.resize(5 + epc.size() + passwd.size() + data.size());

    payload[index++] = (byte)epc.size();
    Array::copy(epc, 0, payload, index, epc.size());
    index += epc.size();

    payload[index++] = (byte) mem_bank;
    payload[index++] = (byte) (address >> 8);
    payload[index++] = (byte) address;
    Array::copy(passwd, 0, payload, index, passwd.size());
    index += passwd.size();

    payload[index++] = (byte)data.size();
    Array::copy(data, 0, payload, index, data.size());
    index += data.size();

    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_TAG_FUNCTIONS,
            RFE_COM2_WRITE_TO_TAG, payload);
    if (res != true){
        Global::trc(_MinimumTraceLevel, "Write To Tag - NOK - Send");
        return res;
    }

    // wait for either the response or a timeout
    bool result = false;
    std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_TAG_FUNCTIONS,
            RFE_COM2_WRITE_TO_TAG), _ResponseTimeOut * 4, result);
    if (!result){
        Global::trc(_MinimumTraceLevel, "Write To Tag - NOK - Resp");
        return false;
    }

    // parse the response
    if (payl.size() == 0 || ((eRFE_RET_VALUE)payl[0])
            != RFE_RET_SUCCESS)
    {
        Global::trc(_MinimumTraceLevel, "Write To Tag - NOK - Payl");
        _LastReturnCode = (eRFE_RET_VALUE) payl[0];
        return false;
    }

    Global::trc(_MinimumTraceLevel, "Write To Tag - OK");

    return true;
}

/// <summary>
/// Locks a specfied memory region of a tag.
/// </summary>
/// <param name="epc">EPC of the specified tag</param>
/// <param name="mode">The lock mode</param>
/// <param name="memory">The memory region</param>
/// <param name="password">The access password to lock the tag</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::lockTag(std::vector<byte> epc, byte mode, byte memory, std::vector<byte> password)
{
    Global::trc(_MinimumTraceLevel, "Lock Tag - Trying to lock tag " + StringHelper::toString(epc) + " with the mode "
            + StringHelper::toIntString(mode) + " the memory " + StringHelper::toIntString(memory));

    if (password.size() != 4){
        Global::trc(_MinimumTraceLevel, "Lock Tag - NOK - Data");
        return false;
    }

    int index = 0;
    std::vector<byte> payload;
    payload.resize(3 + epc.size() + password.size());

    payload[index++] = (byte)epc.size();
    Array::copy(epc, 0, payload, index, epc.size());
    index += epc.size();

    payload[index++] = (byte) mode;
    payload[index++] = (byte) memory;
    Array::copy(password, 0, payload, index, password.size());
    index += password.size();

    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_TAG_FUNCTIONS,
            RFE_COM2_LOCK_TAG, payload);
    if (res != true){
        Global::trc(_MinimumTraceLevel, "Lock Tag - NOK - Send");
        return res;
    }

    // wait for either the response or a timeout
    bool result = false;
    std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_TAG_FUNCTIONS,
            RFE_COM2_LOCK_TAG), _ResponseTimeOut * 2, result);
    if (!result){
        Global::trc(_MinimumTraceLevel, "Lock Tag - NOK - Resp");
        return false;
    }

    // parse the response
    if (payl.size() == 0 || ((eRFE_RET_VALUE)payl[0])
            != RFE_RET_SUCCESS)
    {
        Global::trc(_MinimumTraceLevel, "Lock Tag - NOK - Payl");
        _LastReturnCode = (eRFE_RET_VALUE) payl[0];
        return false;
    }

    Global::trc(_MinimumTraceLevel, "Lock Tag - OK");

    return true;
}

/// <summary>
/// Kills a tag
/// </summary>
/// <param name="epc">EPC of the specified tag</param>
/// <param name="rfu">rfu</param>
/// <param name="recom">recom</param>
/// <param name="password">The kill password to kill the tag</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::killTag(std::vector<byte> epc, byte rfu, byte recom, std::vector<byte> password)
{
    Global::trc(_MinimumTraceLevel, "Kill Tag - Trying to kill tag " + StringHelper::toString(epc) + " with the rfu "
            + StringHelper::toIntString(rfu) + " the recom " + StringHelper::toIntString(recom));

    if (password.size() != 4){
        Global::trc(_MinimumTraceLevel, "Kill Tag - NOK - Data");
        return false;
    }

    int index = 0;
    std::vector<byte> payload;
    payload.resize(2 + epc.size() + password.size());

    payload[index++] = (byte)epc.size();
    Array::copy(epc, 0, payload, index, epc.size());
    index += epc.size();

    payload[index++] = (byte) (  ( (byte) ((rfu & 0x0F) << 4) ) | ( (byte) (recom & 0x0F) )  );
    Array::copy(password, 0, payload, index, password.size());
    index += password.size();

    _LastReturnCode = RFE_RET_SUCCESS;

    // send the command
    bool res = send2Reader(RFE_COM1_TAG_FUNCTIONS,
            RFE_COM2_KILL_TAG, payload);
    if (res != true){
        Global::trc(_MinimumTraceLevel, "Kill Tag - NOK - Send");
        return res;
    }

    // wait for either the response or a timeout
    bool result = false;
    std::vector<byte> payl = _MessageQueue.waitForMessage(messageId(RFE_COM1_TAG_FUNCTIONS,
            RFE_COM2_KILL_TAG), _ResponseTimeOut * 2, result);
    if (!result){
        Global::trc(_MinimumTraceLevel, "Kill Tag - NOK - Resp");
        return false;
    }

    // parse the response
    if (payl.size() == 0 || ((eRFE_RET_VALUE)payl[0])
            != RFE_RET_SUCCESS)
    {
        Global::trc(_MinimumTraceLevel, "Kill Tag - NOK - Payl");
        _LastReturnCode = (eRFE_RET_VALUE) payl[0];
        return false;
    }

    Global::trc(_MinimumTraceLevel, "Kill Tag - OK");

    return true;

}



//*********************************************************************** Getter & Setter
eRFE_RET_VALUE CPPrfeProtocolHandler::lastReturnCode() const
{
    return _LastReturnCode;
}

int CPPrfeProtocolHandler::responseTimeOut() const
{
    return _ResponseTimeOut;
}

void CPPrfeProtocolHandler::setResponseTimeOut(int ResponseTimeOut)
{
    _ResponseTimeOut = ResponseTimeOut;
}

bool CPPrfeProtocolHandler::blockCyclicInventoryInterrupts() const
{
    return _BlockCyclicInventoryInterrupts;
}

void CPPrfeProtocolHandler::setBlockCyclicInventoryInterrupts(bool BlockCyclicInventoryInterrupts)
{
    _BlockCyclicInventoryInterrupts = BlockCyclicInventoryInterrupts;
}

int CPPrfeProtocolHandler::minimumTraceLevel() const
{
    return _MinimumTraceLevel;
}

void CPPrfeProtocolHandler::setMinimumTraceLevel(int MinimumTraceLevel)
{
    _MinimumTraceLevel = MinimumTraceLevel;
}



//*********************************************************************** Output
/// <summary>
/// Builds up a message that is sent to the reader
/// </summary>
/// <param name="com1">Command byte 1</param>
/// <param name="com2">Command byte 2</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::send2Reader(byte com1, byte com2)
{
    std::vector<byte> msg;
    msg.push_back(RFE_START_BYTE_1);
    msg.push_back(RFE_START_BYTE_2);
    msg.push_back(RFE_START_BYTE_3);
    msg.push_back(RFE_COMMAND_START_BYTE);
    msg.push_back(com1);
    msg.push_back(com2);
    msg.push_back(RFE_LENGTH_START_BYTE);
    msg.push_back(0);
    msg.push_back(RFE_CHECKSUM_START_BYTE);
    msg.push_back(calcXORCS(msg));

    _MessageQueue.clearMessage(messageId(com1, com2));

    Global::trc(8, "<- SinglMessage " + StringHelper::toString(msg));

    return _Device->send(msg);
}


/// <summary>
/// Builds up a message that is sent to the reader
/// </summary>
/// <param name="com1">Command byte 1</param>
/// <param name="com2">Command byte 2</param>
/// <param name="payload">Paylod of the message</param>
/// <returns>Success of the operation</returns>
bool CPPrfeProtocolHandler::send2Reader(byte com1, byte com2, std::vector<byte> payload)
{
    std::vector<byte> msg;
    msg.push_back(RFE_START_BYTE_1);
    msg.push_back(RFE_START_BYTE_2);
    msg.push_back(RFE_START_BYTE_3);
    msg.push_back(RFE_COMMAND_START_BYTE);
    msg.push_back(com1);
    msg.push_back(com2);
    msg.push_back(RFE_LENGTH_START_BYTE);
    msg.push_back((byte)payload.size());

    if (payload.size() > 0)
    {
        msg.push_back(RFE_PAYLOAD_START_BYTE);
        msg.insert(msg.end(), payload.begin(), payload.end());
    }

    msg.push_back(RFE_CHECKSUM_START_BYTE);
    msg.push_back(calcXORCS(msg));

    _MessageQueue.clearMessage(messageId(com1, com2));

    Global::trc(8, "<- SinglMessage " + StringHelper::toString(msg));

    return _Device->send(msg);
}

//*********************************************************************** Input
/// <summary>
/// Parses the recieved paylod for the heartbeat interrupt
/// </summary>
/// <param name="payload">The received payload</param>
void CPPrfeProtocolHandler::heartBeatISR(const std::vector<byte>& payload)
{
    if (payload.size() < 1 || ((eRFE_RET_VALUE)payload[0]) != RFE_RET_SUCCESS)
        return;

    if (m_eventListener != 0)
    {
        std::vector<byte> data;
        data.resize(payload.size()-1);
        Array::copy(payload, 1, data, 0, payload.size() - 1);
        m_eventListener->HeartBeatHandler(data);
    }
}


/// <summary>
/// Parses the recieved payload for the cyclic inventory interrupt
/// </summary>
/// <param name="payload">The received payload</param>
void CPPrfeProtocolHandler::cyclicInventoryISR(const std::vector<byte>& payload)
{
    if (_BlockCyclicInventoryInterrupts == true)
        return;

    if(m_eventListener != 0)
    {
        CPPrfeTagEvent tagEvent;
        bool ok = parseTagEvent(payload, tagEvent);

        if (!ok)
            return;

        m_eventListener->CyclicInventoryHandler(tagEvent);
    }
}

/// <summary>
/// Parses the recieved payload for the state changed interrupt
/// </summary>
/// <param name="payload">The received payload</param>
void CPPrfeProtocolHandler::stateChangedISR(const std::vector<byte>& payload)
{
    if (payload.size() != 1)
        return;

    eRFE_CURRENT_READER_STATE state = (eRFE_CURRENT_READER_STATE)payload[0];

    if(m_eventListener != 0)
        m_eventListener->StateChangedHandler(state);
}

/// <summary>
/// Parses the recieved payload for the status register changed interrupt
/// </summary>
/// <param name="payload">The received payload</param>
void CPPrfeProtocolHandler::statusRegChangedISR ( const std::vector<byte>& payload )
{
    if (payload.size() != 8)
        return;

    ulonglong statusRegister = 0;
    statusRegister |= (((ulonglong) payload[0]) << 56);
    statusRegister |= (((ulonglong) payload[1]) << 48);
    statusRegister |= (((ulonglong) payload[2]) << 40);
    statusRegister |= (((ulonglong) payload[3]) << 32);
    statusRegister |= (((ulonglong) payload[4]) << 24);
    statusRegister |= (((ulonglong) payload[5]) << 16);
    statusRegister |= (((ulonglong) payload[6]) << 8);
    statusRegister |= (ulonglong) payload[7];

    if(m_eventListener != 0)
        m_eventListener->StatusRegisterChangedHandler(statusRegister);
}

/// <summary>
/// Parses the recieved payload for the gpio values changed interrupt
/// </summary>
/// <param name="payload">The received payload</param>
void CPPrfeProtocolHandler::gpioValuesChangedISR ( const std::vector<byte>& payload )
{
    if (payload.size() != 4)
        return;

    ulong gpioValues = 0;
    gpioValues |= (((ulong) payload[0]) << 24);
    gpioValues |= (((ulong) payload[1]) << 16);
    gpioValues |= (((ulong) payload[2]) << 8);
    gpioValues |= (ulong) payload[3];

    if (m_eventListener != 0)
        m_eventListener->GpioValuesChangedHandler(gpioValues);
}

/// <summary>
/// Parses the received palyoad for the notification data
/// </summary>
/// <param name="payload">The received payload</param>
void CPPrfeProtocolHandler::notificationISR(const std::vector<byte>& payload)
{
    if (payload.size() < 1)
        return;

    if (m_eventListener != 0)
        m_eventListener->NotificationHandler(payload);
}

/// <summary>
/// Parses the recieved payload for the application ISR
/// </summary>
/// <param name="payload">The received payload</param>
void CPPrfeProtocolHandler::aplicationISR(const std::vector<byte>& payload)
{
    if (payload.size() < 1)
        return;

    if (m_eventListener != 0)
        m_eventListener->ApplicationEventHandler(payload);
}

/// <summary>
/// Parses the recieved payload for the operation result
/// </summary>
/// <param name="payload">The received payload</param>
void CPPrfeProtocolHandler::operationResultISR(const std::vector<byte>& payload)
{
    if (payload.size() < 2)
        return;

    byte id = (byte)payload[0];
    std::vector<byte> data;
    data.resize(payload.size() -1);
    Array::copy(payload, 1, data, 0, payload.size() - 1);

    _PendingMessageQueue.enqueueMessage(id, data);
}


/// <summary>
/// Parses the received bytes from the device and splits it up to sngle messages.
/// </summary>
/// <param name="sender">Sender of the event</param>
/// <param name="data">Data that where sent by the device</param>
void CPPrfeProtocolHandler::dataReadHandler(const std::vector<byte>& data)
{
    Global::trc(10, "-> RawMessage: " + StringHelper::toString(data));

    for(uint i = 0; i < data.size(); i++)
    {
        byte c = data.at(i);

        switch (_state)
        {
        case START_BYTE_1:
            if (c == RFE_START_BYTE_1)
            {
                _state = START_BYTE_2;
                _singleMsg.clear();
                _payloadIndex = 0;
                _payloadLength = 0;
            }
            break;

        case START_BYTE_2:
            if (c == RFE_START_BYTE_2)
                _state = START_BYTE_3;
            else
                _state = START_BYTE_1;
            break;

        case START_BYTE_3:
            if (c == RFE_START_BYTE_3)
                _state = COMMAND_START_BYTE;
            else
                _state = START_BYTE_1;
            break;

        case COMMAND_START_BYTE:
            if (c == RFE_COMMAND_START_BYTE)
                _state = COMMAND_1;
            else
                _state = START_BYTE_1;
            break;

        case COMMAND_1:
            _state = COMMAND_2;
            break;

        case COMMAND_2:
            _state = LENGTH_START_BYTE;
            break;

        case LENGTH_START_BYTE:
            if (c == RFE_LENGTH_START_BYTE)
                _state = LENGTH;
            else
                _state = START_BYTE_1;
            break;

        case LENGTH:
            _payloadLength = c;
            _payloadIndex = 0;
            if (_payloadLength == 0)
                _state = CHECKSUM_START_BYTE;
            else
                _state = PAYLOAD_START_BYTE;
            break;

        case PAYLOAD_START_BYTE:
            if (c == RFE_PAYLOAD_START_BYTE)
                _state = PAYLOAD;
            else
                _state = START_BYTE_1;
            break;

        case PAYLOAD:
            if (++_payloadIndex >= _payloadLength)
                _state = CHECKSUM_START_BYTE;

            break;

        case CHECKSUM_START_BYTE:
            if (c == RFE_CHECKSUM_START_BYTE)
                _state = CHECKSUM;
            else
                _state = START_BYTE_1;
            break;

        case CHECKSUM:
        {
            _state = START_BYTE_1;
            if (c != calcXORCS(_singleMsg))
            {
                Global::trc(0, "CHECKSUM NOK!!");
                break;
            }

            Global::trc(9, "-> SingleMessage: " + StringHelper::toString(_singleMsg));

            computeMessage(_singleMsg);

            break;
        }

        }
        _singleMsg.push_back(c);
    }

}

/// <summary>
/// Computes a single message and stores it in the message queue or computes it.
/// </summary>
/// <param name="msg">A single message from the reader</param>
void CPPrfeProtocolHandler::computeMessage(const std::vector<byte> &msg)
{
    byte command1 = msg[RFE_COMMAND_INDEX_1];
    byte command2 = msg[RFE_COMMAND_INDEX_2];

    std::vector<byte> payload;
    payload.resize(msg.at(RFE_LENGTH_INDEX));
    Array::copy(msg, RFE_PAYLOAD_INDEX, payload, 0, msg[RFE_LENGTH_INDEX]);

    switch (command1)
    {
    case RFE_COM1_INTERRUPT: // Interrupts
        switch (command2)
        {
        case RFE_COM2_HEARTBEAT_INTERRUPT:
            heartBeatISR(payload);
            break;
        case RFE_COM2_INVENTORY_CYCLIC_INTERRUPT:
            cyclicInventoryISR(payload);
            break;
        case RFE_COM2_STATE_CHANGED_INTERRUPT:
            stateChangedISR(payload);
            break;
        case RFE_COM2_STATUS_REG_CHANGED_INTERRUPT:
            statusRegChangedISR(payload);
            break;
        case RFE_COM2_GPIO_PINS_CHANGED:
            gpioValuesChangedISR(payload);
            break;
        case RFE_COM2_NOTIFICATION_INTERRUPT:
            notificationISR(payload);
            break;
        case RFE_COM2_APPLICATION_INTERRUPT:
            aplicationISR(payload);
            break;
        case RFE_COM2_OPERATION_RESULT_INTERRUPT:
            operationResultISR(payload);
            break;

        default:
            _MessageQueue.enqueueMessage(messageId(command1, command2), payload);
            break;
        }
        break;
    default:
        _MessageQueue.enqueueMessage(messageId(command1, command2), payload);
        break;
    }
}


//*********************************************************************** TagEvent
/// <summary>
/// Parses a tag event out of a payload part
/// </summary>
/// <param name="payload">Payload part</param>
/// <param name="ok">Result of parsing</param>
/// <returns>Returns the parsed tag event</returns>
bool CPPrfeProtocolHandler::parseTagEvent(const std::vector<byte>& payload, CPPrfeTagEvent &tagEvent)
{
    typedef enum
    {
        START,
        TAGID_LENGTH,
        TAGID,
        RSSI1,
        RSSI2,
        MEM_BANK,
        MEM_ADDR1,
        MEM_ADDR2,
        MEM_SIZE,
        MEM_DATA,
        TRIGGER,
        ANTENNA,
        FREQUENCY1,
        FREQUENCY2,
        FREQUENCY3,
        HANDLE1,
        HANDLE2,
        STATE1,
        STATE2,
        BATTERY,
        PC1,
        PC2,
        MESSAGE_ID,
        APPLICATION_SIZE,
        APPLICATION_DATA
    } INVENTORY_STATE;

    INVENTORY_STATE state = START;

    byte tagIdIndex = 0;
    byte memIndex = 0;
    byte appInfoIndex = 0;

    for(uint i = 0; i < payload.size(); i++)
    {
        byte c = payload.at(i);

        switch (state)
        {
        case START:
            if (c == RFE_TAG_ID_START_BYTE)
                state = TAGID_LENGTH;
            else if (c == RFE_RSSI_START_BYTE)
                state = RSSI1;
            else if (c == RFE_MEM_START_BYTE)
                state = MEM_BANK;
            else if (c == RFE_TRIGGER_START_BYTE)
                state = TRIGGER;
            else if (c == RFE_ANTENNA_ID_START_BYTE)
                state = ANTENNA;
            else if (c == RFE_READ_FREQU_START_BYTE)
                state = FREQUENCY1;
            else if (c == RFE_GEN2_HANDLE_START_BYTE)
                state = HANDLE1;
            else if (c == RFE_STATE_START_BYTE)
                state = STATE1;
            else if (c == RFE_BATTERY_START_BYTE)
                state = BATTERY;
            else if (c == RFE_GEN2_PC_START_BYTE)
                state = PC1;
            else if (c == RFE_MESSAGE_ID_START_BYTE)
                state = MESSAGE_ID;
            else if (c == RFE_APPLICATION_START_BYTE)
                state = APPLICATION_SIZE;
            else
                state = START;
            break;

        case TAGID_LENGTH:
            tagEvent.tagId.resize(c);
            if (c > 0)
                state = TAGID;
            else
                state = START;
            break;
        case TAGID:
            tagEvent.tagId[tagIdIndex++] = c;
            if (tagEvent.tagId.size() == tagIdIndex)
                state = START;
            break;

        case RSSI1:
            tagEvent.rssi.resize(2);
            tagEvent.rssi[0] = c;
            state = RSSI2;
            break;
        case RSSI2:
            tagEvent.rssi[1] = c;
            tagEvent.hasRSSI = true;
            state = START;
            break;

        case MEM_BANK:
            tagEvent.memBank = c;
            state = MEM_ADDR1;
            break;
        case MEM_ADDR1:
            tagEvent.memAddr = 0;
            tagEvent.memAddr += (ushort)(((ushort)c) << 8);
            state = MEM_ADDR2;
            break;
        case MEM_ADDR2:
            tagEvent.memAddr += c;
            state = MEM_SIZE;
            break;
        case MEM_SIZE:
            tagEvent.memData.resize(c);
            state = MEM_DATA;
            break;
        case MEM_DATA:
            tagEvent.memData[memIndex++] = c;
            if (tagEvent.memData.size() == memIndex)
            {
                state = START;
                tagEvent.hasMemory = true;
            }
            break;

        case TRIGGER:
            tagEvent.trigger = c;
            tagEvent.hasTrigger = true;
            state = START;
            break;

        case ANTENNA:
            tagEvent.antennaId = c;
            tagEvent.hasAntenna = true;
            state = START;
            break;

        case FREQUENCY1:
            tagEvent.readFrequency = 0;
            tagEvent.readFrequency += (((ulong)c) << 16);
            state = FREQUENCY2;
            break;
        case FREQUENCY2:
            tagEvent.readFrequency += (((ulong)c) << 8);
            state = FREQUENCY3;
            break;
        case FREQUENCY3:
            tagEvent.readFrequency += (((ulong)c) << 0);
            tagEvent.hasReadFrequency = true;
            state = START;
            break;

        case STATE1:
            tagEvent.state = 0;
            tagEvent.state += (ushort)(((ushort)c) << 8);
            state = STATE2;
            break;
        case STATE2:
            tagEvent.state += (ushort)(((ushort)c) << 0);
            tagEvent.hasState = true;
            state = START;
            break;

        case HANDLE1:
            tagEvent.handle.resize(2);
            tagEvent.handle[0] = c;
            state = HANDLE2;
            break;
        case HANDLE2:
            tagEvent.handle[1] = c;
            tagEvent.hasHandle = true;
            state = START;
            break;

        case BATTERY:
            tagEvent.battery = c;
            tagEvent.hasBattery = true;
            state = START;
            break;

        case PC1:
            tagEvent.pc.resize(2);
            tagEvent.pc[0] = c;
            state = PC2;
            break;
        case PC2:
            tagEvent.pc[1] = c;
            tagEvent.hasPC = true;
            state = START;
            break;

        case MESSAGE_ID:
            tagEvent.messageId = c;
            tagEvent.hasMessageId = true;
            state = START;
            break;

        case APPLICATION_SIZE:
            tagEvent.applicationInfo.resize(c);
            state = APPLICATION_DATA;
            break;
        case APPLICATION_DATA:
            tagEvent.applicationInfo[appInfoIndex++] = c;
            if (tagEvent.applicationInfo.size() == appInfoIndex)
            {
                state = START;
                tagEvent.hasApplicationInfo = true;
            }
            break;
        }
    }

    if (tagEvent.tagId.size() == 0)
        return false;

    return true;
}




//*********************************************************************** Helper
/// <summary>
/// Generates a unique message id for the command bytes
/// </summary>
/// <param name="command1">Command byte 1</param>
/// <param name="command2">Command byte 2</param>
/// <returns>Unique message id</returns>
ushort CPPrfeProtocolHandler::messageId(byte command1, byte command2)
{
    return (((int)command1) << 8) | command2;
}


/// <summary>
/// Caclulates the XOR checksum for the given data.
/// </summary>
/// <param name="data">The data to calc checksum</param>
/// <returns>The XOR checksum</returns>
byte CPPrfeProtocolHandler::calcXORCS(std::vector<byte> data)
{
    byte result = 0;
    for(uint i = 0; i < data.size(); i++)
    {
        byte c = data.at(i);
        result ^= c;
    }
    return result;
}

//*********************************************************************** EventListener
void CPPrfeProtocolHandler::setEventListener(CPPrfeProtocolHandler::EventListener *eventListener)
{
    m_eventListener = eventListener;
}


